package system;

import invite.Invite;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.mail.MessagingException;
import javax.sound.sampled.LineUnavailableException;

import location.GeoIP;
import log.ChatLog;
import log.ConvitesLog;
import log.EmailsLog;
import log.Log;
import log.SmsLog;
import sms.SmsMessage;
import user.User;
import user.UserControl;
import user.Loggable;
import validator.CoordinatesValidator;
import validator.EmailValidator;
import validator.IPValidator;
import validator.PasswordValidator;
import validator.UserValidator;
import voice.MessagePlayer;
import voice.StopRecordingFactory;
import voice.StopRecordingIF;
import voice.VoiceMessage;
import voice.VoiceMessageIdentification;
import data.DataBase;
import email.Email;
import email.EmailMessage;
import encrypting.EncryptSystem;
import encrypting.SHA1Encrypt;
import exceptions.AttributeNotModifiableException;
import exceptions.DataFileException;
import exceptions.InvalidEMailException;
import exceptions.InvalidIPAdressException;
import exceptions.InvalidLatLongCoordinatesException;
import exceptions.InvalidUserNameException;
import exceptions.LoginActionErrorException;
import exceptions.NonExistentSessionException;
import exceptions.NotFriendException;
import exceptions.NotRegisteredUserException;
import exceptions.NotUpdatableUserException;
import exceptions.UnknownLocationException;
import exceptions.UserAlreadyInvitedException;
import exceptions.UserAlreadySharedException;
import exceptions.UserNameAlreadyExistentException;
import exceptions.UserNotFoundException;

/**
 * This class implements a Application of the system I'm here!
 * 
 * @author Alexandre, Cristovao, Raul, Rodolpho, Tales
 * 
 */
public class AppSystem {

	/**
	 * The default admin's username of the system
	 */
	public static final String ADMIN_USERNAME = "admin";
	
	/**
	 * The default admin's password of the system.
	 */
	public static final String ADMIN_PASSWORD = "adminpasswd";
	
	/**
	 * The default username's password of the system.
	 */
	public static final String SENHA_PADRAO = "123456";
	
	/**
	 * The default line separator of the system
	 */
	public static final String LINE_SEPARATOR = System
			.getProperty("line.separator");
	
	private final String STANDARD_USER = "iam@email.com";

	private Email email;
	private DataBase dataBase;
	private UserControl userControl;
	Log logService = new Log(new EmailsLog());

	private GeoIP geoIPService;

	private Chat chat;
	private boolean chatOn = false;

	private static AppSystem system = null;

	/**
	 * Constructor of the class.
	 */
	protected AppSystem() {
		dataBase = DataBase.getInstance();
		userControl = UserControl.getInstance();

		try {
			this.geoIPService = GeoIP.getInstance();
			// this.onLineGeoIP = true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			// Fix something here.
			// this.onLineGeoIP = false;

		}
	}

	public static synchronized AppSystem getInstance() {
		if (system == null) {
			system = new AppSystem();
		}
		return system;
	}

	/**
	 * This method register a user in the system.
	 * 
	 * @param user
	 *            - a user that will be registered in the system.
	 * @throws Exception
	 *             - if username already exists.
	 */
	public void userRegister(/* UserLoggable user */String userName,
			String nome, String email, String senha, String telefone)
			throws Exception {
		UserValidator.checkAndValidateUserName(userName);
		UserValidator.checkMissingName(nome);
		EmailValidator.checkAndValidateEmail(email);
		PasswordValidator.checkAndValidatePassword(senha);

		EncryptSystem encrypt = EncryptSystem.getInstance();
		encrypt.setEncryptTye(new SHA1Encrypt());
		String encryptedPassword = encrypt.encryptWord(senha);
		Loggable user = null;
		try {
			getUserByUserName(userName);
			throw new UserNameAlreadyExistentException("O username jah existe.");
		} catch (UserNotFoundException e) {
			user = new User(userName, nome, email, encryptedPassword, telefone);
		}

		userControl.insertUser(user);
		if (!getUserByUserName(user.getUserName()).equals(user)) {
			rollBack(user);
			throw new NotRegisteredUserException("Couldn't register the user.");
		}
	}

	/**
	 * Update data of the user.
	 * 
	 * @param user
	 *            - a user that will have his datas updated.
	 * @param modifiedUser
	 *            - the user already modified.
	 * @return a updated user
	 * @throws NotUpdatableUserException
	 *             - if cannot update the user.
	 * @throws InvalidUserNameException
	 * @throws UserNotFoundException
	 */

	public void updateUser(String userName, int attribute, String newValue)
			throws Exception {
		Loggable user = getUserByUserName(userName);

		switch (attribute) {
		case User.ATTR_NAME:
			UserValidator.checkMissingName(newValue);
			break;
		case User.ATTR_EMAIL:
			EmailValidator.checkAndValidateEmail(newValue);
			break;
		case User.ATTR_PASSWORD:
			PasswordValidator.validatePassword(newValue);
			EncryptSystem encrypt = EncryptSystem.getInstance();
			String encryptedPassword = encrypt.encryptWord(newValue);
			newValue = encryptedPassword;
			break;
		case User.ATTR_USERNAME:
			throw new AttributeNotModifiableException(
					"Nao eh permitido alterar o username.");
		default:
			break;
		}

		user.updateAttribute(attribute, newValue);
	}

	/**
	 * Find a user by his name
	 * 
	 * @param name
	 *            - the name of the user
	 * @throws Exception
	 *             - if the user not exists
	 */
	public List<Loggable> findUserByName(String name) throws Exception {
		List<Loggable> returnList = new ArrayList<Loggable>();
		Iterator<String> keysIt = userControl.getUsers().keySet().iterator();
		while (keysIt.hasNext()) {
			String userName = keysIt.next();
			if (getUserByUserName(userName).getName().toLowerCase().contains(
					name.toLowerCase())) {
				returnList.add(getUserByUserName(userName));
			}
		}
		if (returnList.size() == 0) {
			throw new UserNotFoundException("O usuario nao existe.");
		}
		return returnList;
	}

	/**
	 * This method remove a user from the system
	 * 
	 * @param user
	 *            - the user that will have removed.
	 * @throws UserNotFoundException
	 *             - if the user wasn't found.
	 * @throws InvalidUserNameException
	 *             - if the user is invalid.
	 */
	public void deleteUser(String user) throws UserNotFoundException,
			InvalidUserNameException {
		// get the user
		Loggable user1 = getUserByUserName(user);
		Loggable current;
		// set-up the subject and message of an email message
		String message = "Seu amigo "
				+ user1.getName()
				+ ", cancelou a conta que tinha no Im Here ou foi banido do sistema."
				+ LINE_SEPARATOR
				+ "Ele(a) foi removido da sua lista de amigos automaticamente.";
		String subject = user1.getName() + " cancelou a conta do Im Here";
		// get the user's friends list
		List<Loggable> friends = user1.getFriendsList();
		Iterator<Loggable> itr = friends.iterator();
		// iterates through the friends list and send an email (for those who
		// want to receive system notifications) saying that the user is no
		// longer available on Im Here
		while (itr.hasNext()) {
			current = itr.next();
			if (user1.getNotificationMode()) {
				// uncomment the next try/catch block to send the mail

				// try {
				// email.sendEMail(current.getEmail(), subject, message);
				// } catch (MessagingException e) {
				// e.printStackTrace();
				// }

			}
		}

		userControl.removeUserByUserName(user);
	}

	/**
	 * Returns the system to last known good configuration.
	 * 
	 * @param user
	 *            - the last good configuration from the user
	 * @throws InvalidUserNameException
	 *             - if the user is invalid.
	 * @throws UserNotFoundException
	 *             - if the user wasn't found.
	 */
	private void rollBack(Loggable user) throws InvalidUserNameException,
			UserNotFoundException {

		userControl.removeUserByUserName(user.getUserName());

	}

	/**
	 * Cleans the Data Controller
	 */
	public void clean() {
		userControl.clear();

	}

	/**
	 * Clean all logs of the system.
	 */
	public void cleanLogs() {

		String directory = ".";
		FilenameFilter filter = new FilenameFilter() {

			public boolean accept(File dir, String name) {
				return (name.endsWith(".log"));
			}
		};
		File dir = new File(directory);
		String[] list = dir.list(filter);
		File file;
		if (list.length == 0) {
			return;
		}
		for (int i = 0; i < list.length; i++) {
			file = new File(list[i]);
			if (file.exists() && file.isFile()) {
				file.delete();
			}
		}
	}

	/**
	 * Clean the database of the system
	 */
	public void cleanData() {
		dataBase.cleanData();
	}

	/**
	 * Sign in a user in the system.
	 * 
	 * @param userName
	 *            - the user that wants to do login on the system.
	 * @param password
	 *            - the password of the user.
	 * @param ip
	 *            - the user's current IP
	 * @return the logged username
	 * @throws Exception
	 *             - if username or password is invalid.
	 */
	public String login(String userName, String password, String ip)
			throws Exception {

		IPValidator.validateIP(ip);
		Loggable user = null;
		String encryptedPassword = "";
		try {
			user = getUserByUserName(userName);
			EncryptSystem encryptSystem = EncryptSystem.getInstance();
			encryptSystem.setEncryptTye(new SHA1Encrypt());
			encryptedPassword = encryptSystem.encryptWord(password);
		} catch (Exception e) {
			throw new LoginActionErrorException("Login/senha invalidos.");
		}

		if (password == null || password == ""
				|| !user.getPassword().equals(encryptedPassword)) {
			throw new LoginActionErrorException("Login/senha invalidos.");
		}
		user.setIP(ip);
		if (userControl.getLoggedUserByUserName(userName) == null) {
			userControl.insertLoggedUser(user);
			List<Loggable> friends = user.getFriendsList();
			Iterator<Loggable> itr = friends.iterator();
			Loggable current;
			// send a warning to all online friends saying that this user is
			// online right now, just like IM clients such msn, where a
			// warning is displayed when any of your friends logs on the
			// system
			while (itr.hasNext()) {
				current = itr.next();
				if (isLogged(current.getUserName())) {
					// calling the listener
					current.receiveOnlineFriendWarning(user);
				}
			}
			return userName;
		}
		return userName;
	}

	/**
	 * Sign in a user in the system.
	 * 
	 * @param userName
	 *            - the user that wants to do login on the system.
	 * @param password
	 *            - the password of the user.
	 * @return the logged username
	 * @throws Exception
	 *             - if username or password is invalid.
	 */
	public String login(String userName, String password) throws Exception {
		String ipAdress;
		// gets automatic internet IP, not local IP
		try {
			URL url = new URL("http://whatismyip.com/automation/n09230945.asp");
			HttpURLConnection conection = (HttpURLConnection) url
					.openConnection();
			conection.connect();
			BufferedReader page = new java.io.BufferedReader(
					new java.io.InputStreamReader(conection.getInputStream()));
			ipAdress = page.readLine();
			page.close();

		} catch (Exception e) {
			ipAdress = null;
		}
		return login(userName, password, ipAdress);
	}

	/**
	 * This method knows if a user is logged or no
	 * 
	 * @param userName
	 * @return true - if the user is logged false - if the user isn't logged
	 * @throws InvalidUserNameException
	 *             - if the username isn't exists or is invalid.
	 */
	public boolean isLogged(String userName) throws InvalidUserNameException {
		return (userControl.getLoggedUserByUserName(userName) != null) ? true
				: false;
	}

	/**
	 * Logout the user.
	 * 
	 * @param userName
	 *            - the user that want to logout
	 * @throws Exception
	 *             - if the username isn't logged
	 */
	public void logout(String userName) throws Exception {
		if (userControl.getLoggedUserByUserName(userName) != null) {
			userControl.removeLoggedUserByUserName(userName);
			Loggable user = getUserByUserName(userName);
			List<Loggable> friends = user.getFriendsList();
			Iterator<Loggable> itr = friends.iterator();
			Loggable current;
			// send a warning to all online friends saying that this user is
			// offline right now, just like the online warning, but this time is
			// called a offline warning
			while (itr.hasNext()) {
				current = itr.next();
				// current.setOfflineFriend(user);
				if (isLogged(current.getUserName()))
					// calls the offline listener
					current.receiveOfflineFriendWarning(user);
			}
		} else {
			throw new NonExistentSessionException("Sessao inexistente.");
		}
	}

	/**
	 * Returns the current mode of the GeoIP.
	 * 
	 * @return the mode of the GeoIP.
	 */
	public String getGeoIPMode() {
		return "[GeoIP, Manual]";
	}

	/**
	 * Get the location of a user
	 * 
	 * @param userName
	 *            - the user that you want get his location
	 * @return the location of the userName (latitude and longitude)
	 * @throws Exception
	 *             - if the location of the user isn't
	 */
	public String getLocation(String userName) throws Exception {

		Loggable user = getUserByUserName(userName);
		String ip = user.getIp();
		if (user.getLocation().equals("Localizacao desconhecida.")) {
			this.setLocation(userName, geoIPService.getLatitude(ip),
					geoIPService.getLongitude(ip));
			throw new UnknownLocationException(
					"Nao foi possivel obter a localizacao.");
		}
		return getUserByUserName(userName).getLocation();
	}

	/**
	 * Set a location of the user
	 * 
	 * @param userName
	 *            - the username of the user that you will get his location
	 * @param latitude
	 *            - the latitude of the user
	 * @param longitude
	 *            - the longitude of the user
	 * @throws Exception
	 *             - if the username doesn`t exists or latitude/longitude is
	 *             invalid.
	 */
	public void setLocation(String userName, String latitude, String longitude)
			throws Exception {
		int lat = (int) Double.parseDouble(latitude);
		int longi = (int) Double.parseDouble(longitude);

		CoordinatesValidator.validateCoordinates(lat, longi);
		getUserByUserName(userName).setLocation(latitude, longitude);

	}

	/**
	 * Create a single instance of the email system 
	 */
	public void createEmailInstance() {
		email = Email.getInstance();
	}

	/**
	 * Create a chat instance of the chat system
	 */
	public void createChatSystem() {
		chat = new Chat();
	}

	/**
	 * Create a SMS instance of the SMS system
	 */
	public void createSmsSystem() {
		// To do according to sms implementation
	}


	/**
	 * Set the path of the invitations message. This calls the method
	 * setInvitePath(newPath) of DataController
	 * 
	 * @param diretorio
	 *            - the new path of the invitations message
	 */
	public void setDiretorioGabaritos(String diretorio) {
		Invite.setInvitePath(diretorio);
	}

	/**
	 * Return a path of the invitations message This calls the method
	 * getInvitePath() of DataController
	 * 
	 * @return path - the path of the invitations message
	 */
	public String getAnswersPath() {
		return Invite.getInvitePath();
	}

	/**
	 * Confirm the sharing between two users.
	 * 
	 * @param from
	 *            - the user that request a sharing
	 * @param with
	 *            - the user that you
	 * @param mode
	 *            - the mode of the sharing. (1) HIDDEN / (2) VISIBLE
	 * @throws UserAlreadySharedException
	 *             - if both users already are friends
	 * @throws UserNotFoundException
	 * @throws MessagingException
	 */
	public void confirmSharing(String from, String with, int mode)
			throws UserAlreadySharedException, UserNotFoundException {
		Loggable user1 = null;
		Loggable user2 = null;
		user1 = getUserByUserName(from);
		user2 = getUserByUserName(with);
		user1.insertFriend(user2, User.EXIBIR);

		if (mode == User.EXIBIR) {
			user2.insertFriend(user1, User.EXIBIR);
		} else if (mode == User.OCULTAR) {
			user2.insertFriend(user1, User.OCULTAR);
		}
		user2.removePendingInvitation(user1.getEmail());
	}

	/**
	 * Set the sharing between two users.
	 * 
	 * @param userName
	 *            - the user that request the sharing
	 * @param friend
	 *            - the user that will receive the request
	 * @param mode
	 *            - the mode of the exibition. (0)-HIDDEN // (2)-VISIBLE
	 * @throws InvalidUserNameException
	 *             - if the username is invalid or doesn`t exists.
	 * @throws UserNotFoundException
	 */
	public void setSharing(String userName, String friend, int mode)
			throws UserNotFoundException {
		Loggable user = getUserByUserName(friend);
		if (mode == User.EXIBIR) {
			user.setSharing(getUserByUserName(userName), User.EXIBIR);
		} else if (mode == User.OCULTAR) {
			user.setSharing(getUserByUserName(userName), User.OCULTAR);
		}
	}

	/**
	 * Remove a friend from the userlist.
	 * 
	 * @param userName
	 *            - the user that want remove a friend.
	 * @param friend
	 *            - the friend that will be removed from the userlist
	 * @throws Exception
	 *             - if a error occurs.
	 */
	public void removeFriend(String userName, String friend) throws Exception {
		try {
			Loggable userFriend = getUserByUserName(friend);
			getUserByUserName(userName).removeFriend(userFriend);
			userFriend.removeFriend(getUserByUserName(userName));
		} catch (UserNotFoundException ex) {
			throw new Exception("Permissao negada.");
		} catch (NotFriendException e) {
			throw new Exception(e.getMessage());
		}

	}

	/**
	 * Send an invitation to someone.
	 * 
	 * @param from
	 *            - the user who request the invitation
	 * @param to
	 *            - the user who will receive the invitation
	 * @return Returns a success or no about the send of the invitation
	 * @throws UserAlreadyInvitedException
	 * @throws InvalidUserNameException
	 * @throws MessagingException
	 * @throws InvalidEMailException
	 * @throws UserNotFoundException
	 */
	public String sendInvitation(String from, String to)
			throws UserAlreadyInvitedException, MessagingException,
			InvalidEMailException, UserNotFoundException {

		try {
			EmailValidator.validateEmail(to);
			Loggable user = getUserByUserName(from);
			Invite invite1 = new Invite(user.getName(), user.getEmail(), to);
			user.addPendingInvitation(invite1);

			sendEmail(STANDARD_USER, to, invite1.getSubject(), invite1
					.getMessage(), true);

			return "Documento convite.txt enviado com sucesso.";
		} catch (IOException ex) {
			return "Erro ao enviar convite.txt." + ex.getMessage();
		}
	}

	/**
	 * Send an email. This Method internally calls the other sendEmail(see
	 * below) method with parameter isInvite = false, that means that this
	 * method is called when a regular email should be send
	 * 
	 * @param from
	 *            the user that will send the message
	 * @param to
	 *            the user that will receive the message
	 * @param subject
	 *            the subject of the message
	 * @param message
	 *            message that will be send.
	 * @return Success or failure of the message sent
	 */
	public String sendEmail(String from, String to, String subject,
			String message) {
		try {
			Loggable user1 = getUserByUserName(from);
			Loggable user2 = getUserByUserName(to);
			return sendEmail(user1.getEmail(), user2.getEmail(), subject,
					message, false);
		} catch (Exception e) {
			return "Usuario nao encontrado.";
		}
	}

	/**
	 * Send an email based on the fact that the email may be a regular email or
	 * an invitation email and do the proper treatment
	 * 
	 * @param from
	 *            the user that will send the message
	 * @param to
	 *            the user that will receive the message
	 * @param subject
	 *            the subject of the message
	 * @param message
	 *            message that will be send.
	 * @param isInvite
	 *            true if the email is an invitation email or false if is a
	 *            regular email
	 * 
	 * @return Success or failure of the message sent
	 * @throws MessagingException
	 */

	public String sendEmail(String from, String to, String subject,
			String message, boolean isInvite) throws MessagingException {

		if (isInvite) {
			logService.setService(new ConvitesLog());
		} else {
			logService.setService(new EmailsLog());
		}

		EmailMessage emailMsg = new EmailMessage(from, to, subject, message);
		// send a real email, the process may take a while
		// >> uncomment(comment) the following line if you want to send (or not)
		// the real email

		// this.email.sendEMail(emailMsg);

		// save the email message into a log file (just for testing purposes)

		return logService.addLog(emailMsg.getFinalMessage());
	}

	/**
	 * Send a SMS to some user.
	 * 
	 * @param from
	 *            - the user who will send a SMS message
	 * @param to
	 *            - the user who will receive a SMS sended to his cellphone
	 * @param message
	 *            - the message
	 * @return Success or failure about the message send
	 * @throws UserNotFoundException
	 */
	public String sendSMS(String from, String to, String message)
			throws UserNotFoundException {

		Loggable userFrom;
		Loggable userTo;
		userFrom = getUserByUserName(from);
		userTo = getUserByUserName(to);

		// create and send a "sms message"
		SmsMessage smsMessage = new SmsMessage(userFrom.getName(), userTo
				.getPhoneNumber(), message);
		smsMessage.sendMessage();
		// saves a log file
		logService.setService(new SmsLog());
		return logService.addLog(smsMessage.getFinalMessage());
	}

	/**
	 * Refuse sharing between two users.
	 * 
	 * @param from
	 *            - user who request the sharing
	 * @param with
	 *            - user who refuse the sharing
	 * @throws MessagingException
	 * @throws UserNotFoundException
	 */
	public void refuseSharing(String from, String with)
			throws MessagingException, UserNotFoundException {
		Loggable user1 = getUserByUserName(from);
		Loggable user2 = getUserByUserName(with);
		user2.removePendingInvitation(user1.getEmail());
	}

	/**
	 * Get a friend location.
	 * 
	 * @param userName
	 *            - user who request a friend location
	 * @param friendUserName
	 *            - friend of user
	 * @return location of the friend
	 * @throws Exception
	 *             - if user or friend is invalid or not found.
	 */
	public String getFriendLocation(String userName, String friendUserName)
			throws Exception {
		try {
			Loggable friendUser = getUserByUserName(friendUserName);
			Loggable user = getUserByUserName(userName);
			if (!user.isFriend(friendUser))
				throw new Exception("Usuario desconhecido.");
			if (user.canISeeYourLocation(friendUser)) {
				return friendUser.getLocation();
			} else {
				return "Localizacao desconhecida.";
			}
		} catch (UserNotFoundException e) {
			throw new Exception("Permissao negada.");
		}

	}

	/**
	 * Get a user by username
	 * 
	 * @param userName
	 *            - the username of the user that will be searched
	 * @return user
	 * @throws InvalidUserNameException
	 *             - if the user wasn't found or is a invalid username
	 * @throws UserNotFoundException
	 */
	public Loggable getUserByUserName(String userName)
			throws UserNotFoundException {
		Loggable user = userControl.getUserByUserName(userName);
		return user;
	}

	/**
	 * Save current system in database.
	 * 
	 * @throws DataFileException
	 */
	public void saveSystem() throws DataFileException {
		dataBase.saveData();
	}

	/**
	 * Load the database in system.
	 * 
	 * @throws DataFileException
	 */
	public void loadSystem() throws DataFileException {
		clean();
		dataBase.loadData();
	}

	/**
	 * Get all users registered in database
	 * 
	 * @return users
	 */
	public Map<String, Loggable> getUsers() {
		return userControl.getUsers();
	}

	/**
	 * Set a port of the CHAT
	 * 
	 * @param port
	 */
	public void setPortChat(int port) {
		chat.setPortChat(port);
	}

	/**
	 * Initialize a CHAT between two users.
	 * 
	 * @param user1
	 * @param user2
	 */
	public void initChat(String user1, String user2) {
		chatOn = true;
		chat.initChat(user1, user2);
	}

	/**
	 * Send a message to a user
	 * 
	 * @param to
	 *            - user that will receive the message
	 * @param message
	 */
	public void sendMessage(String to, String message) {
		chat.sendMessage(to, message);
	}

	/**
	 * Receive a message from a user
	 * 
	 * @param from
	 *            the user that sent the message
	 * @return the message
	 */
	public String getMessage(String from) {
		return chat.getMessage(from);
	}

	/**
	 * Finish a chat session between two users
	 * 
	 * @param user1
	 * @param user2
	 */
	public void finishChat(String user1, String user2) {
		// chat.createLogFile();
		logService.setService(new ChatLog(user1, user2));
		logService.addLog(chat.getLogChat());

		chat = new Chat();
		chatOn = false;
	}

	/**
	 * Get a user attribute
	 * @param userName the name of the user
	 * @param attribute - the type of the attribute
	 * @return the current value on the attribute
	 * @throws InvalidUserNameException - if the username don't exists
	 * @throws UserNotFoundException - if the user won't find
	 */
	public String getUserAttribute(String userName, int attribute)
			throws InvalidUserNameException, UserNotFoundException {
		Loggable user = getUserByUserName(userName);
		return user.getAttribute(attribute);
	}

	/**
	 * Send a voice message
	 * @param from the user that will send the audio message
	 * @param to the user that will receives the audio message
	 * @throws UserNotFoundException - if the user won't find
	 * @throws LineUnavailableException - if the line is unavailable
	 */
	public void sendVoiceMessage(String from, String to)
			throws UserNotFoundException, LineUnavailableException {

		Loggable userTo = getUserByUserName(to);
		VoiceMessageIdentification msgId = new VoiceMessageIdentification(from,
				to, getDate(), getTime());
		VoiceMessage message = new VoiceMessage(msgId);
		StopRecordingIF action = StopRecordingFactory.createTextAction();
		message.startRecording();
		action.showAction();
		message.stopRecording();
		userTo.addVoiceMessage(msgId);

	}
	
	/**
	 * Plays the audio message.
	 * @param msgId - the ID of the audio message
	 * @throws MalformedURLException - if any problem occurs.
	 */
	public void playMessage(VoiceMessageIdentification msgId)
			throws MalformedURLException {
		MessagePlayer player = new MessagePlayer(msgId.getFileName());
		player.playMessage();
	}

	/**
	 * Get the ID of the message.    
	 * @param userName the username
	 * @param index
	 * @return the message on the index
	 * @throws UserNotFoundException - if the user won't find.
	 */
	public VoiceMessageIdentification getMessageId(String userName, int index)
			throws UserNotFoundException {
		Loggable user = getUserByUserName(userName);
		return user.getMessage(index);

	}

	/**
	 * Get all voice messages of the user
	 * @param userName
	 * @return all voice messages
	 * @throws UserNotFoundException - if the user won't find.
	 */
	public List<VoiceMessageIdentification> getVoiceMessages(String userName)
			throws UserNotFoundException {
		Loggable user = getUserByUserName(userName);
		return user.getVoiceMessages();
	}

	/**
	 * Get the current date of the calendar
	 * @return the current date in format dd.mmmm.yyyy
	 */
	private String getDate() {
		Calendar cal = Calendar.getInstance();
		int year = cal.get(Calendar.YEAR);
		int month = cal.get(Calendar.MONTH);
		int day = cal.get(Calendar.DAY_OF_MONTH);
		return day + "." + month + "." + year;
	}

	/**
	 * Get the current time of the calendar
	 * @return current hour, in format hh:mm:ss.miliseconds
	 */
	private String getTime() {
		Calendar cal = Calendar.getInstance();
		int hour = cal.get(Calendar.HOUR_OF_DAY);
		int minute = cal.get(Calendar.MINUTE);
		int second = cal.get(Calendar.SECOND);
		int millisecond = cal.get(Calendar.MILLISECOND);
		return hour + ":" + minute + ":" + second + "." + millisecond;

	}

}